const express = require("express");
// const https = require("https");
const path = require("path");
const cors = require("cors");
const compression = require("compression");
const rateLimit = require("express-rate-limit");
const morgan = require("morgan");
const helmet = require("helmet");
require("dotenv").config();

// 自定义模块
const jx = require("./utils/jwt");
const { CODE, Response } = require("./utils/response");

// 路由导入
const routes = {
  user: require("./routes/user"),
  admin_user: require("./routes/admin_user"),
  space: require("./routes/space"),
  comments:require('./routes/comments'),
   doc:require('./routes/doc'),
  upload: require("./routes/upload"),
  route: require("./routes/route"),
  permission: require("./routes/permission"),
  department: require("./routes/department"),
};

// 常量配置
const WHITELISTED_ROUTES = [
  "/user/login",
  "/user/register",
  "/user/auth/check",
  "/user/logout",
  "/user/refresh",
];
const PORT = process.env.PORT || 3000;

// 初始化 Express 应用
const app = express();

// ======================
// 中间件配置
// ======================

/**
 * 安全相关中间件
 */
function configureSecurityMiddleware() {
  // 安全头设置
  app.use(
    helmet({
      crossOriginResourcePolicy: { policy: "cross-origin" },
      crossOriginEmbedderPolicy: false,
    })
  );

  // 速率限制
  const limiter = rateLimit({
    windowMs: 15 * 60 * 1000, // 15分钟
    max: 1000, // 限制每个IP 15分钟内最多100个请求
  });
  app.use(limiter);
}

/**
 * 性能优化中间件
 */
function configurePerformanceMiddleware() {
  // 启用 GZIP 压缩
  app.use(compression());
}

/**
 * CORS 配置
 */
function configureCors() {
  const corsOptions = {
    origin: true, // 允许来自任何源的请求
    credentials: true,
    methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
    allowedHeaders: ["Content-Type", "Authorization", "X-Requested-With"],
    exposedHeaders: ["Content-Range", "X-Content-Range"],
    maxAge: 86400, // 预检请求缓存1天
  };

  app.use(cors(corsOptions));
  app.options("*", cors(corsOptions));
}

/**
 * 请求解析中间件
 */
function configureRequestParsing() {
  app.use(express.urlencoded({ extended: false }));
  app.use(express.json({ limit: "10mb" }));
}

/**
 * 日志记录中间件
 */
function configureLogging() {
  app.use(
    morgan(
      "[:date[clf]] :method :url :status :response-time ms - :res[content-length]"
    )
  );
}

// ======================
// 自定义中间件
// ======================

/**
 * Token 验证中间件
 */
/**
 * Token 验证中间件
 */
async function checkToken(req, res, next) {
  if (WHITELISTED_ROUTES.includes(req.path)) {
    return next();
  }

  const token = req.headers.authorization || "";

  if (!token) {
    return res
      .status(CODE.UNAUTHORIZED)
      .json(Response.error(CODE.UNAUTHORIZED, "未携带 token", "TOKEN_MISSING"));
  }

  try {
    const decoded = await jx.verifyToken(token);
    const currentTimestamp = Math.floor(Date.now() / 1000);

    if (decoded.exp && decoded.exp < currentTimestamp) {
      return res
        .status(CODE.UNAUTHORIZED)
        .json(
          Response.error(CODE.UNAUTHORIZED, "Token已过期", "TOKEN_EXPIRED")
        );
    }

    req.user = decoded;
    next();
  } catch (err) {
    // 判断是否为撤销错误
    if (err.message === "Token已被撤销") {
      return res
        .status(CODE.UNAUTHORIZED)
        .json(
          Response.error(CODE.UNAUTHORIZED, "Token已被撤销", "TOKEN_REVOKED")
        );
    }

    return res
      .status(CODE.UNAUTHORIZED)
      .json(
        Response.error(
          CODE.UNAUTHORIZED,
          err.message || "无效的 token",
          "TOKEN_INVALID"
        )
      );
  }
}

/**
 * 静态文件服务配置
 */
function configureStaticFiles() {
  app.use(
    "/public",
    (req, res, next) => {
      res.set({
        "Access-Control-Allow-Origin": "*",
        "Access-Control-Allow-Methods": "GET, OPTIONS",
        "Access-Control-Allow-Headers":
          "Content-Type, Authorization, X-Requested-With",
        "Access-Control-Allow-Credentials": "true",
      });
      next();
    },
    express.static(path.join(__dirname, "public"), {
      maxAge: "1d",
      etag: true,
      setHeaders: (res, path, stat) => {
        res.set("Cross-Origin-Resource-Policy", "cross-origin");
      },
    })
  );
}

/**
 * 404 处理中间件 - 检查路由是否存在
 */
function checkRouteExists(req, res, next) {
  const path = req.path.replace("/BHapi", "");
  const routeExists = Object.values(routes).some((router) => {
    return router.stack.some((layer) => {
      if (layer.route) {
        const routePath = layer.route.path;
        return path === routePath || path.startsWith(routePath + "/");
      }
      return false;
    });
  });

  if (!routeExists) {
    return res
      .status(CODE.NOT_FOUND)
      .json(Response.error(CODE.NOT_FOUND, `接口 ${req.originalUrl} 不存在`));
  }
  next();
}

/**
 * 错误处理中间件
 */
function errorHandler(err, req, res, next) {
  console.error(`[Error] ${err.stack}`);

  let statusCode = err.status || CODE.SERVER_ERROR;
  let message = err.message;

  // 处理特定类型的错误
  if (err.name === "ValidationError") {
    statusCode = CODE.VALIDATE_ERROR;
  } else if (err.name === "UnauthorizedError") {
    statusCode = CODE.UNAUTHORIZED;
  } else if (err.name === "ForbiddenError") {
    statusCode = CODE.FORBIDDEN;
  }

  // 在生产环境下隐藏详细错误信息
  if (
    process.env.NODE_ENV === "production" &&
    statusCode === CODE.SERVER_ERROR
  ) {
    message = ERROR_MSG[CODE.SERVER_ERROR];
  }

  res
    .status(statusCode)
    .json(
      Response.error(
        statusCode,
        message,
        process.env.NODE_ENV !== "production" ? err.stack : undefined
      )
    );
}

// ======================
// 应用配置
// ======================

// 配置中间件
configureSecurityMiddleware();
configurePerformanceMiddleware();
configureCors();
configureRequestParsing();
configureLogging();
configureStaticFiles();

// API 路由
app.use("/BHapi", checkToken, checkRouteExists, Object.values(routes));

// 其他路径的 404 处理
app.use((req, res) => {
  console.log(`404 Not Found: ${req.originalUrl}`);
  res
    .status(CODE.NOT_FOUND)
    .json(Response.error(CODE.NOT_FOUND, `路径 ${req.originalUrl} 不存在`));
});

// 错误处理
app.use(errorHandler);

// ======================
// 启动服务器
// ======================

app.listen(PORT, () => {
  console.log(`API server running at http://127.0.0.1:${PORT}`);
});
